#include <jni.h>
#include <string.h>
#include <stdio.h>
#include <android/log.h>
#include "MyManager.h"

#define  LOG_TAG    "ClientSdk"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

typedef struct
{
	JavaVM * pJavaVM;
	jclass  class_mediator;
	jmethodID user_event;
	jmethodID wb_data;
	jobject  pObj;
}CallbackHolder;

static CallbackHolder g_callbackHolder;
static CMyManager	*g_man = NULL;

extern "C"
{
	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_InitLib(JNIEnv * env, jobject obj);
	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_ReleaseLib(JNIEnv * env, jobject obj);

	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_StartApp(JNIEnv * env, jobject obj, jint inTerminalId, jbyteArray inSerIp, jint inPort);
	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_StopApp(JNIEnv * env, jobject obj);

	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_Login(JNIEnv * env, jobject obj, jbyteArray inUserName, jbyteArray inPassword);

	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_GetUserInfo(JNIEnv * env, jobject obj);
	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_GetUserList(JNIEnv * env, jobject obj);

	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_GetMeetingFileList(JNIEnv * env, jobject obj);
	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_GetMeetingIssueList(JNIEnv * env, jobject obj);

	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_GetMeetingVoteList(JNIEnv * env, jobject obj);
	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_TerminalUserSign(JNIEnv * env, jobject obj, jint inUserId, jbyteArray inUserName, jbyteArray inFilePath, jbyteArray inFileName);

	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_UserSignControl(JNIEnv * env, jobject obj, jint nControlType);
	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_AllUserSign(JNIEnv * env, jobject obj, jbyteArray inJson);

	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_IssueControl(JNIEnv * env, jobject obj, jint nIssueId, jint nControlType); 

	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_VoteControl(JNIEnv * env, jobject obj, jint nVoteId, jint nControlType);
	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_VoteMsg(JNIEnv * env, jobject obj, jbyteArray inJson);

	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_CenterControl(JNIEnv * env, jobject obj, jint nControlType);

	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_SendChatMessage(JNIEnv * env, jobject obj, jbyteArray inJson);
	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_SendMeetingService(JNIEnv * env, jobject obj, jbyteArray inJson);

	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_DownLoadFile(JNIEnv * env, jobject obj, jbyteArray inSavePath, jbyteArray inServerPath);
	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_UpLoadFile(JNIEnv * env, jobject obj, jbyteArray inFilePath, jbyteArray inFileName, jint inFileType);

	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_SendWbData(JNIEnv * env, jobject obj, jbyteArray inWbData);
	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_SendCommentData(JNIEnv * env, jobject obj, jbyteArray inWbData);

	JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_SendAndroidControlMsg(JNIEnv * env, jobject obj, jbyteArray inWbData);

};

void OnMsgBack(int nType, const char *pMsg, const int nMsgLen)
{
	if (!g_callbackHolder.pJavaVM)
	{		
		return;
	}		

	JNIEnv *lpEnv = NULL;

	int ret_value = g_callbackHolder.pJavaVM->GetEnv((void**)&lpEnv, JNI_VERSION_1_6);
	if (JNI_EDETACHED == ret_value) 
	{
		if (g_callbackHolder.pJavaVM->AttachCurrentThread((JNIEnv **)&lpEnv, NULL) != 0)
		{
			return;
		}
	}
	else if (JNI_EVERSION == ret_value) 
	{	
		return;
	}

	if (g_callbackHolder.class_mediator && g_callbackHolder.pObj)
	{
		if (nMsgLen > 0)
		{
			if (nType == 34 || nType == 39)
			{
				jbyteArray byteArray = lpEnv->NewByteArray(nMsgLen);
				lpEnv->SetByteArrayRegion(byteArray, 0, nMsgLen, (jbyte*)pMsg);

				lpEnv->CallVoidMethod(g_callbackHolder.pObj, g_callbackHolder.wb_data, nType, byteArray);
			}
			else
			{
				string strUtf = GBKToUtf8(pMsg, nMsgLen);

				jstring str_value = lpEnv->NewStringUTF(strUtf.c_str());
				lpEnv->CallVoidMethod(g_callbackHolder.pObj, g_callbackHolder.user_event, nType, str_value);
			}			
		}
		else
		{
			lpEnv->CallVoidMethod(g_callbackHolder.pObj, g_callbackHolder.user_event, nType, 0);
		}

		if (lpEnv->ExceptionCheck()) 
		{
			lpEnv->ExceptionDescribe();
		}
	}

	if (JNI_EDETACHED == ret_value) 
	{
		g_callbackHolder.pJavaVM->DetachCurrentThread();
	}
}

void MakeGlobalRef(JNIEnv* pEnv, jobject* pRef)
{
	if (*pRef != 0 ) 
	{
		jobject lGlobalRef = pEnv->NewGlobalRef(*pRef);
		pEnv->DeleteLocalRef(*pRef);

		*pRef = lGlobalRef;
	}
}

void DeleteGlobalRef(JNIEnv* pEnv, jobject* pRef)
{
	if (*pRef != 0)
	{
		pEnv->DeleteGlobalRef(*pRef);
		*pRef = 0;
	}
}

JNIEXPORT jint JNICALL  JNI_OnLoad(JavaVM *ajvm, void *reserved)
{
	memset((void*)&g_callbackHolder, 0x00, sizeof(CallbackHolder));
	g_callbackHolder.pJavaVM = ajvm;

	return JNI_VERSION_1_6;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_InitLib(JNIEnv * env, jobject obj)
{
	if (!g_man)
		g_man = new CMyManager(OnMsgBack);

	if (!g_man)
	{
		return -1;
	}		

	if (g_callbackHolder.class_mediator && g_callbackHolder.pObj)
	{
		DeleteGlobalRef(env, (jobject*)&g_callbackHolder.class_mediator);
	}

	g_callbackHolder.class_mediator = env->FindClass("com/paperless/clientsdk/NetSession");
	if (g_callbackHolder.class_mediator)
	{
		MakeGlobalRef(env, (jobject*)&g_callbackHolder.class_mediator);

		g_callbackHolder.user_event = env->GetMethodID(g_callbackHolder.class_mediator, "GetCmdData", "(ILjava/lang/String;)V");
		g_callbackHolder.wb_data = env->GetMethodID(g_callbackHolder.class_mediator, "GetWbData", "(I[B)V");
		g_callbackHolder.pObj = env->NewGlobalRef(obj);

		return 0;
	}

	return -1;	
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_ReleaseLib(JNIEnv * env, jobject obj)
{
	if (g_man)
	{
		delete g_man;
		g_man = NULL;
	}

	return 0;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_StartApp(JNIEnv * env, jobject obj, jint inTerminalId, jbyteArray inSerIp, jint inPort)
{
	int nRet = -1;
	char *pServerIP = (char *)(env)->GetByteArrayElements(inSerIp, 0);
	int nServerLen = env->GetArrayLength(inSerIp);

	if (!pServerIP)
		return nRet;
	
	if (!g_man)
		return nRet;

	char szServerIP[16] = { 0 };
	memcpy(szServerIP, pServerIP, nServerLen);

	if (g_man->StartApp(inTerminalId, szServerIP, inPort))
		nRet = 0;
	else
		nRet = -1;

	return nRet;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_StopApp(JNIEnv * env, jobject obj)
{
	if (g_man)
	{
		g_man->Stop();
		return 0;
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_Login(JNIEnv * env, jobject obj, jbyteArray inUserName, jbyteArray inPassword)
{
	if (g_man)
	{
		char *pUserName = (char *)(env)->GetByteArrayElements(inUserName, 0);
		int nUserNameLen = env->GetArrayLength(inUserName);

		char *pPassWrod = (char *)(env)->GetByteArrayElements(inPassword, 0);
		int nPassWordLen = env->GetArrayLength(inPassword);

		if (!pUserName || !pPassWrod)
			return -3;
		
		char szBuf[1024] = { 0 };
		int nBufLen = 1024;

		char szUserName[128] = { 0 };
		char szPassWord[128] = { 0 };
		
		memcpy(szUserName, pUserName, nUserNameLen);
		memcpy(szPassWord, pPassWrod, nPassWordLen);

		string strUserName = Utf8ToGBK(szUserName, nUserNameLen);
		string strPassword = Utf8ToGBK(szPassWord, nPassWordLen);

		int nRet = g_man->UserLogin(strUserName.c_str(), strPassword.c_str(), szBuf, &nBufLen);
		if (nRet != 0)
		{
			OnMsgBack(25, szBuf, nBufLen);
		}

		return nRet;
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_GetUserInfo(JNIEnv * env, jobject obj)
{
	if (g_man)
	{
		int nBuffLen = 1024 * 100;
		char *pBuf = new char[nBuffLen];

		memset(pBuf, 0x00, nBuffLen);

		if (g_man->GetUserInfo(pBuf, &nBuffLen))
		{
			OnMsgBack(8, pBuf, nBuffLen);

			delete[] pBuf;
			pBuf = NULL;

			return 0;
		}

		delete[] pBuf;
		pBuf = NULL;
	}	

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_GetUserList(JNIEnv * env, jobject obj)
{
	if (g_man)
	{
		int nBuffLen = 1024 * 100;
		char *pBuf = new char[nBuffLen];

		memset(pBuf, 0x00, nBuffLen);

		if (g_man->GetUserList(pBuf, &nBuffLen))
		{
			OnMsgBack(9, pBuf, nBuffLen);

			delete[] pBuf;
			pBuf = NULL;

			return 0;
		}

		delete[] pBuf;
		pBuf = NULL;
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_GetMeetingFileList(JNIEnv * env, jobject obj)
{
	if (g_man)
	{
		int nBuffLen = 1024 * 100;
		char *pBuf = new char[nBuffLen];

		memset(pBuf, 0x00, nBuffLen);

		if (g_man->GetMeetingFileList(pBuf, &nBuffLen))
		{
			OnMsgBack(10, pBuf, nBuffLen);

			delete[] pBuf;
			pBuf = NULL;

			return 0;
		}

		delete[] pBuf;
		pBuf = NULL;
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_GetMeetingIssueList(JNIEnv * env, jobject obj)
{
	if (g_man)
	{
		int nBuffLen = 1024 * 100;
		char *pBuf = new char[nBuffLen];

		memset(pBuf, 0x00, nBuffLen);

		if (g_man->GetMeetingIssueList(pBuf, &nBuffLen))
		{
			OnMsgBack(11, pBuf, nBuffLen);

			delete[] pBuf;
			pBuf = NULL;

			return 0;
		}

		delete[] pBuf;
		pBuf = NULL;
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_GetMeetingVoteList(JNIEnv * env, jobject obj)
{
	if (g_man)
	{
		int nBuffLen = 1024 * 100;
		char *pBuf = new char[nBuffLen];

		memset(pBuf, 0x00, nBuffLen);

		if (g_man->GetMeetingVoteList(pBuf, &nBuffLen))
		{
			OnMsgBack(12, pBuf, nBuffLen);

			delete[] pBuf;
			pBuf = NULL;

			return 0;
		}

		delete[] pBuf;
		pBuf = NULL;
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_TerminalUserSign(JNIEnv * env, jobject obj, jint inUserId, jbyteArray inUserName, jbyteArray inFilePath, jbyteArray inFileName)
{
	if (g_man)
	{
		char *pUserName = (char *)(env)->GetByteArrayElements(inUserName, 0);
		int nUserNameLen = env->GetArrayLength(inUserName);

		char *pFilePath = (char *)(env)->GetByteArrayElements(inFilePath, 0);
		int nFilePathLen = env->GetArrayLength(inFilePath);

		char *pFileName = (char *)(env)->GetByteArrayElements(inFileName, 0);
		int nFileNameLen = env->GetArrayLength(inFileName);

		if (!pUserName || !pFilePath || !pFileName)
			return -3;

		char szUserName[128] = { 0 };
		char szFilePath[512] = { 0 };
		char szFileName[256] = { 0 };
		
		memcpy(szUserName, pUserName, nUserNameLen);
		memcpy(szFilePath, pFilePath, nFilePathLen);
		memcpy(szFileName, pFileName, nFileNameLen);

		string strUserName = Utf8ToGBK(szUserName, nUserNameLen);
		string strFilePath = Utf8ToGBK(szFilePath, nFilePathLen);
		string strFileName = Utf8ToGBK(szFileName, nFileNameLen);

		if (g_man->TerminalUserSign(inUserId, strUserName.c_str(), strFilePath.c_str(), strFileName.c_str()))
		{
			return 0;
		}
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_UserSignControl(JNIEnv * env, jobject obj, jint nControlType)
{
	if (g_man)
	{
		if (g_man->UserSignControl(nControlType))
			return 0;
		else
			return -2;
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_AllUserSign(JNIEnv * env, jobject obj, jbyteArray inJson)
{
	if (g_man)
	{
		char *pJson = (char *)(env)->GetByteArrayElements(inJson, 0);
		int nLen = env->GetArrayLength(inJson);

		if (!pJson)
			return -3;

		char *pData = new char[nLen + 1];
		memset(pData, 0x00, nLen + 1);

		memcpy(pData, pJson, nLen);

		string strJson = Utf8ToGBK(pData, nLen);

		if (g_man->AllUserSign(strJson.c_str()))
		{
			delete[] pData;
			pData = NULL;

			return 0;
		}			

		delete[] pData;
		pData = NULL;

		return -2;
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_IssueControl(JNIEnv * env, jobject obj, jint nIssueId, jint nControlType)
{
	if (g_man)
	{
		return g_man->IssueControl(nIssueId, nControlType);
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_VoteControl(JNIEnv * env, jobject obj, jint nVoteId, jint nControlType)
{
	if (g_man)
	{
		return g_man->VoteControl(nVoteId, nControlType);
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_VoteMsg(JNIEnv * env, jobject obj, jbyteArray inJson)
{
	if (g_man)
	{
		char *pJson = (char *)(env)->GetByteArrayElements(inJson, 0);
		int nLen = env->GetArrayLength(inJson);

		if (!pJson)
			return -3;

		char *pData = new char[nLen + 1];
		memset(pData, 0x00, nLen + 1);

		memcpy(pData, pJson, nLen);

		string strGBK = Utf8ToGBK(pData, nLen);

		int nRet = g_man->VoteMsg(strGBK.c_str(), strGBK.length());

		delete[] pData;
		pData = NULL;

		return nRet;
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_CenterControl(JNIEnv * env, jobject obj, jint nControlType)
{
	if (g_man)
	{
		return g_man->CenterControl(nControlType);
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_SendChatMessage(JNIEnv * env, jobject obj, jbyteArray inJson)
{
	if (g_man)
	{
		char *pJson = (char *)(env)->GetByteArrayElements(inJson, 0);
		int nLen = env->GetArrayLength(inJson);

		if (!pJson)
			return -3;

		char *pData = new char[nLen + 1];
		memset(pData, 0x00, nLen + 1);

		memcpy(pData, pJson, nLen);

		string strGBK = Utf8ToGBK(pData, nLen);

		bool bRet = g_man->SendChatMessage(strGBK.c_str());

		delete[] pData;
		pData = NULL;

		if (bRet)
			return 0;
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_SendMeetingService(JNIEnv * env, jobject obj, jbyteArray inJson)
{
	if (g_man)
	{
		char *pJson = (char *)(env)->GetByteArrayElements(inJson, 0);
		int nLen = env->GetArrayLength(inJson);

		if (!pJson)
			return -3;

		char *pData = new char[nLen + 1];
		memset(pData, 0x00, nLen + 1);

		memcpy(pData, pJson, nLen);

		string strGBK = Utf8ToGBK(pData, nLen);

		bool bRet = g_man->SendMeetingService(strGBK.c_str());

		delete[] pData;
		pData = NULL;

		if (bRet)
			return 0;
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_DownLoadFile(JNIEnv * env, jobject obj, jbyteArray inSavePath, jbyteArray inServerPath)
{
	if (g_man)
	{
		char *pSavePath = (char *)(env)->GetByteArrayElements(inSavePath, 0);
		int nSavePathLen = env->GetArrayLength(inSavePath);

		char *pServerPath = (char *)(env)->GetByteArrayElements(inServerPath, 0);
		int nServerPathLen = env->GetArrayLength(inServerPath);

		if (!pSavePath || !pServerPath)
			return -3;

		char szSavePath[256] = { 0 };
		char szServerPath[256] = { 0 };

		memcpy(szSavePath, pSavePath, nSavePathLen);
		memcpy(szServerPath, pServerPath, nServerPathLen);

		string strSavePath = Utf8ToGBK(szSavePath, nSavePathLen);
		string strServerPath = Utf8ToGBK(szServerPath, nServerPathLen);

		return g_man->DownLoadFile(strSavePath.c_str(), strServerPath.c_str());
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_UpLoadFile(JNIEnv * env, jobject obj, jbyteArray inFilePath, jbyteArray inFileName, jint inFileType)
{
	if (g_man)
	{
		char *pFilePath = (char *)(env)->GetByteArrayElements(inFilePath, 0);
		int nFilePathLen = env->GetArrayLength(inFilePath);

		char *pFileName = (char *)(env)->GetByteArrayElements(inFileName, 0);
		int nFileNameLen = env->GetArrayLength(inFileName);

		if (!pFilePath || !pFileName)
			return -3;

		char szFilePath[512] = { 0 };
		char szFileName[512] = { 0 };

		memcpy(szFilePath, pFilePath, nFilePathLen);
		memcpy(szFileName, pFileName, nFileNameLen);

		string strFilePath = Utf8ToGBK(szFilePath, nFilePathLen);
		string strFileName = Utf8ToGBK(szFileName, nFileNameLen);

		return g_man->UpLoadFile(strFilePath.c_str(), strFileName.c_str(), inFileType);
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_SendWbData(JNIEnv * env, jobject obj, jbyteArray inWbData)
{
	if (g_man)
	{
		char *pWbData = (char *)(env)->GetByteArrayElements(inWbData, 0);
		int nWbDataLen = env->GetArrayLength(inWbData);

		if (!pWbData)
			return -3;

		return g_man->SendWbData(pWbData, nWbDataLen);
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_SendCommentData(JNIEnv * env, jobject obj, jbyteArray inWbData)
{
	if (g_man)
	{
		char *pWbData = (char *)(env)->GetByteArrayElements(inWbData, 0);
		int nWbDataLen = env->GetArrayLength(inWbData);

		if (!pWbData)
			return -3;

		return g_man->SendCommentData(pWbData, nWbDataLen);
	}

	return -1;
}

JNIEXPORT jint JNICALL Java_com_paperless_clientsdk_NetSession_SendAndroidControlMsg(JNIEnv * env, jobject obj, jbyteArray inWbData)
{
	if (g_man)
	{
		char *pJson = (char *)(env)->GetByteArrayElements(inWbData, 0);
		int nLen = env->GetArrayLength(inWbData);

		if (!pJson)
			return -3;

		char *pData = new char[nLen + 1];
		memset(pData, 0x00, nLen + 1);

		memcpy(pData, pJson, nLen);

		string strGBK = Utf8ToGBK(pData, nLen);

		bool bRet = g_man->SendExtendData(strGBK.c_str());

		delete[] pData;
		pData = NULL;

		if (bRet)
			return 0;
	}

	return -1;
}
